# To change this template, choose Tools | Templates
# and open the template in the editor.

from hexconfig import *
#from AIbot import *
import sys
sys.setrecursionlimit(10000)



SPLIT_SAVE = False
SPLIT_LOAD = False
#PASSION
#YOSHIDO BROTHERS
ENEMY_POS_DIST_DROPOFF = 0.1
FRIENDLY_POS_DIST_DROPOFF = 0.1

PROPOGATION_LIST_DROPOFF = 0.9
PROPOGATION_SPREAD_DROPOFF = 0.2

PLAYER_STATE_DIFF_CUTOFF = 2
ENEMY_STATE_DIFF_CUTOFF = 2

NUM_CHUNKS = 5

FILENAME2_EDGES = "posttest_edges"
FILENAME2_NODES = "posttest1"
class DataHandler():
    def __init__(self):
        self.fileList = []

    def saveZone(self,name,zone):
        if zone == []:
            print "No Zone to save!"
            return
        #name = ask(self.screen,"Save Zone As?")

        if name == "" or name == "x":
            return
        file = open("../zones/"+name+".pkl",'wb')
        pickle.dump(zone,file)


    def loadZone(self,name):
        if name == "" or name == "x":
            return
        loadFile = open("../zones/"+name+".pkl",'rb')
        return pickle.load(loadFile)


        #THIS IS NOT BEING USED---- will work on when higher on to-do
    def loadBotThoughtRatingHistory(self):
        return pickle.load(open("../aiData/thoughtHistory.png"))

    def autoSaveDataSet(self,dataSet):
        #self.splitSave(dataSet, "split")
        clock = pygame.time.Clock()
        dateTime = "DS_"+strftime("%m_%d(%H-%M)")

        if not SPLIT_SAVE:
            print "SAVING backup at ", dateTime
            p = pickle.Pickler(open("../ai_data/backup_datasets/"+dateTime+"Nodes"+".pkl",'wb'))
            p.fast = True
            p.dump(dataSet.nodes)
            p = pickle.Pickler(open("../ai_data/backup_datasets/"+dateTime+"Edges"+".pkl",'wb'))
            p.fast = True
            p.dump(dataSet.edges)
            #del p
            print "Autosaving..."
            p = pickle.Pickler(open("../ai_data/autosaveNodes.pkl",'wb'))
            p.fast = True
            p.dump(dataSet.nodes)
            p = pickle.Pickler(open("../ai_data/autosaveEdges.pkl",'wb'))
            p.fast = True
            p.dump(dataSet.edges)
        else:
            print "SAVING BACKUP at ", dateTime
            self.splitSave("../ai_data/autosaveNodes"+".pkl"\
                , "../ai_data/backup_datasets/"+dateTime+"Edges"+".pkl",dataSet)
            print "Autosaving...."
            self.splitSave("../ai_data/backup_datasets/"+dateTime+"Nodes"+".pkl"\
                , "../ai_data/autosaveEdges"+".pkl",dataSet)


        ms = clock.tick()
        secs = ms/1000
        mins = secs/60
        print
        print "TIME TO SAVE DATA:",mins," mins,",secs%60 if secs>60 else secs," secs"
        print "NODES_LENGTH",len(dataSet.nodes)
        print "EDGES_LENGTH",len(dataSet.edges)

    

    def autoLoadDataSet(self,surf = None):

        
        clock = pygame.time.Clock()
        if not SPLIT_LOAD:
            #ds = pickle.load(loadFile)
            ds = DataSet()
            loadFile = open("../ai_data/autosaveNodes.pkl",'rb')
            ds.nodes = pickle.load(loadFile)
            #pickle.clear_memo()
            loadFile = open("../ai_data/autosaveEdges.pkl",'rb')
            ds.edges = pickle.load(loadFile)
        else:
            ds = self.splitLoad(surf,"../ai_data/autosaveNodes.pkl","../ai_data/autosaveEdges.pkl")

        #del loadFile
        ms = clock.tick()
        secs = ms/1000
        mins = secs/60
        print
        print "TIME TO LOAD DATA:",mins," mins,",secs%60 if secs>60 else secs," secs"
        print "NODES_LENGTH",len(ds.nodes)
        print "EDGES_LENGTH",len(ds.edges)
        return ds

    #saves a split up version of the file a chunk at a time
    def splitSave(self,nodesFname,edgesFname,data):
        print "SAVING(",NUM_CHUNKS,"pcs): "
        newFileEdges = open("../ai_data/"+FILENAME2_EDGES+".pkl",'wb')
        newFileNodes = open("../ai_data/"+FILENAME2_NODES+".pkl",'wb')
        chunkSize = (len(data.nodes)/NUM_CHUNKS,len(data.edges)/NUM_CHUNKS)
        for i in range(NUM_CHUNKS):
            nodesChunk = []
            edgesChunk = []
            for k in (data.nodes.keys()[i*chunkSize[0]:(i+1)*chunkSize[0]]):
                nodesChunk.append(data.nodes[k])
                #print len(nodesChunk)
            #for k in (data.edges.keys()[i*chunkSize[1]:(i+1)*chunkSize[1]]):
            #    edgesChunk.append(data.nodes[k])
            print "|",
        
            #
            #pickle.dump(edgesChunk, newFileEdges)
            pickle.dump(nodesChunk, newFileNodes)
        print "(DONE)."
        newFileEdges.close()
        newFileNodes.close()

    def splitLoad(self,surf,filenameNodes,filenameEdges):
        loadEdges = open(filenameEdges,'rb')
        loadNodes = open(filenameNodes,'rb')
        ds = DataSet()

        for i in range(NUM_CHUNKS):
            nodesChunk = pickle.load(loadNodes)
            edgeChunk = pickle.load(loadEdges)
            for n in nodesChunk:
                print n
                ds.nodes[decompressStateRLE(n.stateString)] = n
            for e in edgeChunk:
                print  e.n[0]+e.n[1]
                ds.edges[decompressStateRLE(e.n[0])\
                        +decompressStateRLE(e.n[1])] = e

            

            #for n in nodesChunk:
                #put n in dataset
            if not surf == None:
                pygame.draw.rect(surf,(255,0,0),(200,200,(i+1)*64,64))
                pygame.display.flip()
        return ds 







class Replay():
    def __init__(self,moveList,setups,names = ["P0","P1"]):
        self.setups = setups #state string
        self.moveList = moveList #list of lists of moves, seperated per player turn
        self.playerNames = names # Names of players durrr


def mirrorStateString(state,team = 0):
    [p0units, p1units, p0king, p1king] = stateStringToBoard(state,team)
    return boardToStateString(p0units, p1units, p0king, p1king,team,True)

class DataSet():
    def __init__(self):
        self.setup()

    def setup(self):
        self.nodes = nodeDictionary()
        self.edges = edgeDictionary()

    def addFileToDataSet(self, filename):
        loadFile = open("../ai_data/"+filename+"Edges.pkl",'rb')
        newEdges = pickle.load(loadFile)
        for newEdgeKey in newEdges.keys():
            newEdge = newEdges[newEdgeKey]
            self.addEdge(newEdge.n[0], newEdge.n[1], newEdge.a)
        del newEdges
        
        loadFile = open("../ai_data/"+filename+"Nodes.pkl",'rb')
        newNodes = pickle.load(loadFile)
        for nK in newNodes.keys():
            n2 = newNodes[nK]
            if not self.isNodeInGraph(n2.stateString()):
                addedNode = self.addNode(n2.stateString())
                addedNode.u = n2.u
                addedNode.w = n2.w

            else:
                n1 = self.getNode(n2.stateString())
                totalWeight = n1.w+n2.w

                avg = 0.0 if totalWeight == 0.0 else (n1.u+n2.u)/(totalWeight)
                n1.w = max(n1.w,n2.w)
                n1.u = avg*n1.w
        del newNodes
        

    def addDSToDataSet(self, newDataSet):

        print "Adding Edges to Data Set"
        for nK in newDataSet.nodes.keys():
            n2 = newDataSet.nodes[nK]
            if not self.isNodeInGraph(n2.stateString()):
                addedNode = self.addNode(n2.stateString())
                addedNode.u = n2.u
                addedNode.w = n2.w

            else:
                n1 = self.getNode(n2.stateString())
                totalWeight = n1.w+n2.w

                avg = 0.0 if totalWeight == 0.0 else (n1.u+n2.u)/(n1.w+n2.w)
                n1.w = max(n1.w,n2.w)
                n1.u = avg*n1.w
            for e in n2.inEdges():
                edge = newDataSet.getEdgeFromKey(e)
                s1 = e[:43]
                #s1 = edge.n[0]
                s2 = n2.stateString()
                self.addEdge(s1,s2,edge.a)

            for e in n2.outEdges():
                edge = newDataSet.getEdgeFromKey(e)
                s1 = n2.stateString()
                s2 = edge.n[0]

                self.addEdge(s1,s2,edge.a)





    def getAvgOutUtil(self, stateNode):
        total = 0.0
        for nodeString in stateNode.outEdges():
            total+= self.nodes[nodeString].util()
        total/float(len(stateNode.outEdges()))
    

    def isStateInCheck(self, stateString, turn = 0):
        #print
        #print "is state in check?", stateString
        if stateString.find("A") == -1:
            return turn == 0
        if stateString.find("B") == -1 :
            return turn != 0
        alternateStateString = switchStateStringToOtherTeam(stateString, turn)
        #alternateStateString = boardToStateString(p0units, p1units, p0king, p1king, 1 if turn == 0 else 0)
        #spread = False
        #self.spreadStateString(alternateStateString, 0)
        canEnemyWin = self.isStateWinnable(alternateStateString)
        return canEnemyWin

    def isStateWinnable(self, stateString):
        #print "is state winnable?"
        self.spreadStateString(stateString, 0)
        #print "Checking if", self.nodes[stateString], "is winnable"
        return self.isEdgeInGraph(stateString, WIN_NODE_STRING)

    def isNodeInGraph(self,stateString):
        #print stateString
        try:
            self.nodes[stateString]
            return True
        except KeyError:
            return False
        """
        #-----bot not used
        for n in self.nodes:
            if n.stateString == stateString:
                return True

        return False
        """

    def isEdgeInGraph(self,stateStringA,stateStringB):
        edgekey = ""
        edgekey+=stateStringA
        edgekey+=stateStringB

        try:
            #print "key:",edgekey
            self.edges[edgekey]
            #print "found"
            return True
        except KeyError:
            #print "not found"
            return False


    def addNode(self, stateString):
        #print "adding node", stateString
        if self.isNodeInGraph(stateString):
            #print "NODE ALREADY IN GRAPH"
            return
        #node = StateNode(stateString)
        self.nodes[stateString] = StateNode(stateString)
        return self.nodes[stateString]

    def spreadDataSet(self,replayList,desiredDepth):
        #spread the data set at first with just the replays

        for r in replayList:
            #boardStates = getEndBoardStates(r.setups,r.moveList)
            self.addDataWithReplay(r)
        loadBarCount = [0]
        for k in self.nodes.keys()[0:len(self.nodes.keys())/1]:
                self.spreadRecurser(self.nodes[k].stateString(),desiredDepth,loadBarCount)

    def spreadStateNode(self,stateNode,desiredDepth = 0):
        loadBarCount = [0]
        self.spreadRecurser(stateNode.stateString(),desiredDepth,loadBarCount)

    def spreadStateString(self,stateString,desiredDepth = 0):
        loadBarCount = [0]
        self.spreadRecurser(stateString,desiredDepth,loadBarCount)

    def spreadRecurser(self,stateString,desiredDepth,loadBarCount, currentDepth = 0):
        #print "SPREAD_RECURSOR(",stateString,")"#edges: ",len(edges)
        loadBarCount[0]+=1
        if loadBarCount[0]>32:
            loadBarCount[0] = 0
            print "Nodes:",len(self.nodes), "Edges:", len(self.edges)

        if self.getNode(stateString) == None or self.nodes[stateString].l:

            #print stateString
            edges = getAllMovesFromState(stateString)
            #print edges
            for e in edges:
                #print "/te"
                nextState = stateStringFromActionList(stateString,e)
                #print "I'm trying to add:", e, nextState
                """wasNotInGraph = False
                if not self.isNodeInGraph(nextState):
                    wasNotInGraph = True"""
                if teamKilledByActionList(stateString, e)!= 0:
                    self.addEdge(stateString,nextState,e)
                else:
                    continue
                    print "Edge will kill an allied unit!  Not adding to list"
                #print "I added it!"
            #print stateString, "is being spread", self.nodes[stateString].l
            #print stateString
            self.nodes[stateString].l = False
        else:
            pass
            #print stateString, "has already been spread", self.nodes[stateString].isLeaf
        if currentDepth<desiredDepth:
            for edge in self.nodes[stateString].outEdges():
                self.spreadRecurser(self.nodes[edge.n[1]], desiredDepth, loadBarCount,currentDepth+1)

    def fleshOutEdges(self):
        clock = pygame.time.Clock()
        nodeNumber = 0
        printStep = .5
        nextPercent = 0.00001
        lastMilliseconds = 0
        print "getting keys"
        keys = self.nodes.keys()
        print "done getting keys"
        for key in keys:
            node = self.nodes[key]
            #print "Node", nodeNumber, ":", node
            nodeNumber += 1

            if node.l == True:
                edges = getAllMovesFromState(node.stateString())

                for e in edges:
                    nextState = stateStringFromActionList(node.stateString(),e)#THIS CAN BE SPED UP
                    try:
                        self.nodes[nextState]#this is already doing try-except in there but not wrong
                        if not self.isEdgeInGraph(node.stateString(), nextState) and teamKilledByActionList(node.stateString(), e)!= 0:
                            self.addEdge(node.stateString(), nextState, e)
                            #total += 1
                    except KeyError:
                        continue
                
            percent = (1.0*nodeNumber)/(1.0*len(keys))*100.0
            if percent >= nextPercent:
                print nodeNumber, "nodes,",percent, "%",
                ms = clock.tick()-lastMilliseconds
                lastMilliseconds = clock.tick()
                secs = ms/1000
                mins = secs/60
                print mins," mins,",secs%60 if secs>60 else secs," secs"
                nextPercent += printStep


    def addEdge(self,stateStringA,stateStringB,actionList):
        #print "Adding edge", stateStringA, stateStringB
        #print "Action List:", actionList
        if stateStringA == stateStringB:
            #print "You're adding an edge to itself!"
            return


        if not self.isEdgeInGraph(stateStringA, stateStringB):
            if actionList == []:
                print "You're adding an edge with no actionList!"
            #print "the edge is not in the graph"
            #the states dont have to be in the graph
            self.addNode(stateStringA)
            self.addNode(stateStringB)

            nodeA = self.nodes[stateStringA]
            nodeA.addOutEdge(stateStringB)
            nodeB = self.nodes[stateStringB]
            nodeB.addInEdge(stateStringA)

            edge = E(actionList,stateStringA,stateStringB)

            self.edges[stateStringA+stateStringB] = edge
            #print "I'm adding", stateStringA+stateStringB
        else:
            #print "I'm not adding", actionList, "because we already have", self.edges[stateStringA+stateStringB].a
            if len(actionList) > len(self.edges[stateStringA+stateStringB].a):
                self.edges[stateStringA+stateStringB].a = actionList
            #print "the edge is already in the graph"
            pass

    #there should only be a single instance of stateString, possibly store in a dict still, using the
    def getNode(self,stateString):
        try:
            return self.nodes[stateString]#should have it because in addedge where this is called, it adds the nodes for sure ahead of time
        except KeyError:
            #print "No Node with that state-string", stateString
            return None
            
        #for n in self.nodes:
        #    if n.stateString == stateString:
        #        return n

    def getSimilarStates(self, stateString):
        #print "similar? ",stateString
        currentP0Key = getP0KeyString(stateString)
        currentP1Key = getP1KeyString(stateString)
        p0KeyList = []
        
        for k in self.nodes.getP0Keys():
            #print "k:", k
            p0dist = stringDiff(currentP0Key, k)
            if p0dist <= PLAYER_STATE_DIFF_CUTOFF:
                #print "p0:", p0dist, currentP0Key, k
                p0KeyList.append((p0dist, k))
        p1KeyList = []
        retList = []
        for p0Dist, p0Key in p0KeyList:
            states = self.nodes.p0Keys[compressStateRLE(p0Key)].keys()
            for str in states:
                decomp  = decompressStateRLE(str)
                if self.nodes[decomp].l: continue
                p1Key = getP1KeyString(decomp)
                #print p1Key
                p1Dist = stringDiff(p1Key, currentP1Key)
                
                if p1Dist <= ENEMY_STATE_DIFF_CUTOFF:
                    #print "p1:", p1Dist, currentP1Key, p1Key
                    totalDist = p0Dist+p1Dist#math.pow((p0Dist*p0Dist + p1Dist*p1Dist), 0.5)
                    if not totalDist == 0.0 and not decomp == stateString:
                        retList.append(decomp)
                        
                    #retList.append([str,totalDist])
        #for ret in retList:
        #    print ret
        return retList

    def propogateUtilToSimilarStates(self, stateString, util, weight):
        #print "Trying to add stuff to group:", getP0KeyString(stateString)
        similarKeys = self.nodes.p0Keys[compressStateRLE(getP0KeyString(stateString))].keys()
        #similarKeys = self.getSimilarStates(stateString)
        #print "      ", len(similarKeys), "states similar to", stateString
        for k in similarKeys:
            sKey = decompressStateRLE(k)
            node = self.nodes[sKey]
            dist = stringDiff(stateString, sKey)#levStringDiff(stateString, k)
            if dist==0: continue
            adjustedWeight = weight * pow(ENEMY_POS_DIST_DROPOFF, dist)
            node.addUtil(util, adjustedWeight)
            

    def propogateUtil(self, stateList, util, weight = 1.0):
        nodeList = []
        for i in stateList:
            nodeList.append(self.nodes[i])

        for n in range(len(nodeList)):
            if nodeList[n].stateString()[0]=="W": continue   #don't do win node!
            #print " About to call propogateUtilToNode on", stateList[n]
            moveUtil = util*math.pow(PROPOGATION_LIST_DROPOFF,len(nodeList)-n)
            self.propogateUtilToNode(nodeList[n], moveUtil, weight)

    def propogateUtilToNode(self, node, utility, weight):
        if self.addUtilToNode(node, utility, weight):
            #print "propogated", utility, "@", weight, "to", node.stateString()
            for inEdge in node.inEdges():
                inNode = self.getNode(inEdge[:43])#self.edges[inEdge].n[0]
                if inNode:
                    self.propogateUtilToNodeRecurser(inNode, utility, 1, weight, node.stateString())

    def propogateUtilToNodeRecurser(self, node, utility, n, weight, lastNodeString):
        newWeight =  weight * math.pow(PROPOGATION_SPREAD_DROPOFF,n)
        #print "propogatedRec", utility, "@", weight, "to", node.stateString()
        #if self.addUtilToNode(node, utility, newWeight):
        #if (n==0 and self.addUtilToNode(node, utility, newWeight)) or\
        #   (node.addUtil(utility, newWeight)):
        if self.addUtilToNode(node, utility, newWeight):
            #print "spreaddedededed!"
            #print "      Spread to in node:", utility, newWeight, "(",n,")", node.stateString
            newerWeight = newWeight*math.pow(PROPOGATION_SPREAD_DROPOFF,n+1)
            #neverWeight = newWeight*math.pow(PROPOGATION_SPREAD_DROPOFF,n)*math.pow(PROPOGATION_SPREAD_DROPOFF,n+1)
            if newerWeight*utility < ZERO_THRESHOLD: return
            for inEdge in node.inEdges():
                inNode = self.getNode(inEdge[:43])#self.edges[inEdge].n[0]
                if inNode.stateString() == lastNodeString: continue
                if inNode:
                    self.propogateUtilToNodeRecurser(inNode, utility, n+1, newWeight, node.stateString())

    def addUtilToNode(self, node, utility, weight):
        if node.addUtil(utility, weight):
            self.propogateUtilToSimilarStates(node.stateString(), utility, weight)
            return True
        return False

    def getEdgeBetweenNodes(self,nodeA,nodeB):
        #im really not sure if this is a useful function, idk when it would be searched like this
        for e in self.edges:
            if e.n[0] == nodeA and e.n[1] == nodeB:
                return e

    def getEdgeFromKey(self, state):
        try:
            #print "trying to get edge from ", state
            return self.edges[state]
        except KeyError:
            return None

    def getDestinationNodes(self,stateString):
        retList = []
        if self.isNodeInGraph(stateString):
            for e in self.nodes[stateString].outEdges():
                retList.append(e.n[1])

        return retList

    def addDataWithReplay(self,replay):
        #for now just treat the replay as a clumped list of actionlists
        currentState = replay.setups
        turn = 0
        for e in replay.moveList:
            nextState = stateStringFromActionList(currentState,e)
            #print currentState

            #print nextState
            self.addEdge(currentState, nextState, e)
            currentState = nextState


            if nextState[0] == "W":
                return

            p0units, p1units, p0king, p1king = stateStringToBoard(currentState, turn)
            turn = (turn+1)%2

            currentState = boardToStateString(p0units, p1units, p0king, p1king, turn)

        return

    def bothkings(self, move):
        Afound = False
        Bfound = False
        for i in range(len(move)):
            if move[i] == 'A':
                Afound = True
            elif move[i] == 'B':
                Bfound = True
        if not Afound or not Bfound:
            return False
        return True


if __name__ == "__main__":
    
    pygame.init()
    screen = pygame.display.set_mode((SWIDTH,SHEIGHT))#,pygame.FULLSCREEN)#,pygame.HWSURFACE)
    clock = pygame.time.Clock()
    #loadFile = open("../ai_data/autosaveNodes.pkl",'rb')
    #nodes = pickle.load(loadFile)
    #print "loaded nodes:", len(nodes)
    #pickle.Pickler.clear_memo()
    #loadFile = open("../ai_data/autosaveEdges.pkl",'rb')
    #edges = pickle.load(loadFile)
    #print "loaded edges:", len(edges)
    dh = DataHandler()
    ds = DataSet()#dh.autoLoadDataSet()
    dh.autoSaveDataSet(ds)
    exit()
    print "checking!"
    """
    for e in ds.edges.keys():
        #print e
        if len(ds.edges[e].a) == 0:
            print ds.edges[e]
    print "done checking!"

    """
    total = 0
    keys = ds.nodes.keys()
    for n in keys:
        #print originalDS.getNode(n)
        node = ds.nodes[n]
        if n[0] != "W" and (node.u != 0.00 or node.w != 1.0):
            node.u = 0.0
            node.w = 1.0
            total += 1
    print "Removed utility from ", total
    dh.autoSaveDataSet(ds)

    #dh.autoSaveDataSet(ds)
    print "Oh god I'm going to flesh out the whole dataset"
    """for key in ds.nodes.keys():
        ds.nodes[key].u = 0.0
        ds.nodes[key].w = 1.0
    """
    ds.fleshOutEdges()
    print "Nodes",len(ds.nodes)
    print "Edges",len(ds.edges)
    #print "I can't believe we made it to here"
    dh.autoSaveDataSet(ds)
    sys.exit(0)


    ms = clock.tick()
    secs = ms/1000
    mins = secs/60
    print
    print "TIME TO LOAD DATA:",mins," mins,",secs%60 if secs>60 else secs," secs"
    print "NODES_LENGTH",len(ds.nodes)
    print "EDGES_LENGTH",len(ds.edges)

    """
    replaylist = ["04162131"]
    loadedreplaylist = []
    for r in replaylist:
        loadedreplaylist.append(loadReplay(r))
    ds.spreadDataSet(loadedreplaylist, 0)

    ms = clock.tick()
    secs = ms/1000
    mins = secs/60
    print
    print "TIME TO SPREAD DATA:",mins," mins,",secs%mins if secs>60 else secs," secs"
    print "NODES_LENGTH",len(ds.nodes)
    print "EDGES_LENGTH",len(ds.edges)
    dh.autoSaveDataSet(ds)


    clock.tick()
    #ds.fleshOutEdges()

    ms = clock.tick()
    secs = ms/1000
    mins = secs/60
    print
    print "TIME TO FLESH OUT DATA:",mins," mins,",secs%mins if secs>60 else secs," secs"
    print "NODES_LENGTH",len(ds.nodes)
    print "EDGES_LENGTH",len(ds.edges)
    dh.autoSaveDataSet(ds)
    """
    """
    pygame.init()
        #print SWIDTH,",",SHEIGHT
    #if FULLSCREEN:
    screen = pygame.display.set_mode((SWIDTH,SHEIGHT))#,pygame.FULLSCREEN)#,pygame.HWSURFACE)

    nodeA = StateNode("A")
    #nodeA.u+=0.2
    nodeB = StateNode("B")
    nodeC = StateNode("C")
    nodeD = StateNode("D")
    nodeE = StateNode("E")

    edge = E([],nodeE,nodeC)
    edge = E([],nodeD,nodeC)
    edge = E([],nodeC,nodeA)
    edge = E([],nodeB,nodeA)

    #handler = DataHandler()

    #handler.addMirrorsToDataSet()

    ds = DataSet()
    ds.addEdge("E", "C", [])
    ds.addEdge("D", "C", [])
    ds.addEdge("C", "A", [])
    ds.addEdge("B", "A", [])


    print "ADDING UTILY"

    """
    #ds.fleshOutEdges()

    ms = clock.tick()
    secs = ms/1000
    mins = secs/60
    print
    print "TIME TO FLESH OUT DATA:",mins," mins,",secs%60 if secs>60 else secs," secs"
    print "NODES_LENGTH",len(ds.nodes)
    print "EDGES_LENGTH",len(ds.edges)
    dh.autoSaveDataSet(ds)


    """for i in ds.getNode(n).inEdges():
        print "","In",i
    for o in ds.getNode(n).outEdges():
        print "","Out",o"""



